module source.config;

import  std.file : readText, FileException, write;
import  std.conv : to;
import std.stdio : writeln, stderr;
import   std.utf : UTFException;
import  std.json : JSONException, JSONValue, parseJSON;

import sdlang : Tag, parseSource, ParseException, AttributeNotFoundException, TagNotFoundException;

class ConfigManager
{
    private string configpath;
    public string modulepath;

    public string server, loggingPath, nickname, username, realname, quitmsg, pass;
    public int port;
    public bool loggingToggle;
    public string[string] authentication;

    public string prefix, opPrefix;
    public string[string] apiKeys;
    public int[string] accessibility;

    public string[] available, chans, ignored;
    public string[string] chankeys;

    this(string configpath, string modulepath)
    {
        this.configpath = configpath;
        this.modulepath = modulepath;
    }

    public bool reloadConfig()
    {
        Tag root;
        try
        {
            string settingFile;
            {
                try
                {
                    settingFile = to!string(readText(this.configpath~"/settings.sdl"));
                }

                catch (FileException e)
                {
                    stderr.writeln(e.msg);
                    return false;
                }
                catch (UTFException e)
                {
                    stderr.writeln(e.msg);
                    return false;
                }
            }

            root = parseSource(settingFile);
        }

        catch(ParseException e)
        {
            stderr.writeln(e.msg);
            return false;
        }
        try
        {
            this.server = root.getTagValue!string("server", "chat.freenode.net");
            this.port = root.getTagAttribute!int("server", "port", 6667);

            Tag logging = root.getTag("logging");
            this.loggingToggle = logging.getTagValue!bool("toggle", false);
            this.loggingPath = logging.getTagValue!string("logPath", "./output.log");

            Tag ircDetails = root.getTag("ircDetails");
            this.nickname = ircDetails.getTagValue!string("nickname", "DlangIrcBot");
            this.username = ircDetails.getTagValue!string("username", "DlangIrcBot");
            this.realname = ircDetails.getTagValue!string("realname", "A modular irc bot written in dlang");
            this.pass = ircDetails.getTagValue!string("pass", "");
            this.quitmsg = ircDetails.getTagValue!string("quitMessage", "Bye!");

            Tag authentication = root.getTag("authentication");
            this.authentication["method"] = authentication.getTagValue!string("method", "");
            this.authentication["username"] = authentication.getTagValue!string("username", "");
            this.authentication["password"] = authentication.getTagValue!string("password", "");

            Tag plugins = root.getTag("plugins");
            this.prefix = plugins.getTagValue!string("prefix", "!");
            this.opPrefix = plugins.getTagValue!string("opPrefix", "!");
        }
        catch (AttributeNotFoundException e)
        {
            stderr.writeln(e.msg);
            return false;
        }
        catch (TagNotFoundException e)
        {
            stderr.writeln(e.msg);
            return false;
        }

        return true;
    }

    public bool reloadAssets()
    {
        JSONValue root;
        try
        {
            string moduleFile;
            {
                try
                {
                    moduleFile = to!string(readText(this.configpath ~ "/assets.json"));
                }
                catch (FileException e)
                {
                    stderr.writeln(e.msg);
                    return false;
                }
                catch (UTFException e)
                {
                    stderr.writeln(e.msg);
                    return false;
                }
            }

            root = parseJSON(moduleFile);
        }
        catch (JSONException e)
        {
            stderr.writeln(e.msg);
            return false;
        }

        this.available = this.available.init;
        this.ignored = this.ignored.init;

        foreach (string channame, JSONValue key; root["keys"].object)
        {
            this.chans ~= channame;
            this.chankeys[channame] = key.str;
        }

        for (int i = 0; i < root["available"].array.length; i++)
        {
            this.available ~= root["available"][i].str;
        }

        for (int i = 0; i < root["ignored"].array.length; i++)
        {
            this.ignored ~= root["ignored"][i].str;
        }

        foreach (string keyname, JSONValue key; root["apiKeys"].object)
        {
            this.apiKeys[keyname] = key.str;
        }

        foreach (string mask, JSONValue access; root["accessibility"].object)
        {
            this.accessibility[mask] = cast(int)access.integer;
        }

        return true;
    }

    public bool saveAssets()
    {
        JSONValue assets;
        assets["keys"] = this.chankeys;
        assets["accessibility"] = this.accessibility;
        assets["apiKeys"] = this.apiKeys;
        assets["available"] = this.available;
        assets["ignored"] = this.ignored;

        try
        {
            write(this.configpath ~ "/assets.json", assets.toPrettyString);
        }
        catch (FileException e)
        {
            stderr.writeln("Unable to save assets");
            return false;
        }
        return true;
    }
}
